package com.jfok.server.DAO;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import ognl.Ognl;
import ognl.OgnlException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.jfok.server.common.CommonFunction;
import com.jfok.server.common.ModuleServiceFunction;
import com.jfok.server.common.TreeValueText;
import com.jfok.server.common.TypeChange;
import com.jfok.server.common.ValueText;
import com.jfok.server.common.json.JsonDateProcessor;
import com.jfok.server.core.module.SqlField;
import com.jfok.server.core.module.SqlGenerator;
import com.jfok.server.core.module.SqlModuleFilter;
import com.jfok.server.hibernate.addition._Addition;
import com.jfok.server.hibernate.system._Module;
import com.jfok.server.hibernate.system._ModuleField;
import com.jfok.server.hibernate.systemset._SystemOperateLog;
import com.jfok.server.login.SessionManage;
import com.jfok.server.login.UserSession;
import com.jfok.server.service.SystemAndLoginInfoService;
import com.jfok.shared.module.DataFetchRequestInfo;
import com.jfok.shared.module.DataFetchResponseInfo;
import com.jfok.shared.module.ModuleConstants;
import com.jfok.shared.module.grid.GridFilterData;

@Repository
public class ModuleDAO {

	private static final Log log = LogFactory.getLog(ModuleDAO.class);

	@Autowired
	private SystemBaseDAO systemBaseDAO;

	
	public Object getBeanIdWithIdOrName(_Module module, Object idOrName) {
		Object bean = getBeanWithIdOrName(module, idOrName);
		if (bean == null)
			return null;
		else
			try {
				return Ognl.getValue(module.getTf_primaryKey(), bean);
			} catch (OgnlException e) {
				e.printStackTrace();
				return null;
			}
	}

	
	public Object getBeanWithIdOrName(_Module module, Object idOrName) {
		Class<?> BeanClass = ModuleServiceFunction.getModuleBeanClass(module.getTf_moduleName());
		Object bean = null;
		try {
			bean = systemBaseDAO.findById(BeanClass, idOrName);
		} catch (Exception e) {
		}
		if (bean == null) {
			try {
				List<?> beans = systemBaseDAO
						.findByProperty(BeanClass, module.getTf_nameFields(), idOrName);
				if (beans.size() == 1)
					bean = beans.get(0);
				else if ((beans.size() > 1))
					return null;
			} catch (Exception e) {
			}
		}
		if (bean == null) {
			try {
				@SuppressWarnings("unchecked")
				List<Object> beans = systemBaseDAO.findByLikeProperty(BeanClass.getSimpleName(),
						module.getTf_nameFields(), "%" + idOrName + "%");
				if (beans.size() == 1)
					bean = beans.get(0);
			} catch (Exception e) {
			}
		}
		return bean;
	}

	

	@SuppressWarnings("unchecked")
	public void updateValueToBean(String moduleName, Object record, JSONObject keyValue)
			throws OgnlException {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
		Iterator<String> keyIterator = keyValue.keys();
		while (keyIterator.hasNext()) {
			String key = keyIterator.next();
			Object value = keyValue.get(key);
			// 是不是manytoone 的值进行了修改
			if (key.indexOf(ModuleConstants.SEPARATOR) != -1) {

				String[] table_fieldname = key.split(ModuleConstants.SEPARATOR);
				_Module parentModule = module.getModuleWithAsName(table_fieldname[0]);
				if (value instanceof JSONNull) { // 如果是父模块的manytoone字段没有选择，则只更新到前面
					key = "tf" + parentModule.getTf_moduleNameWithPre();
				} else {
					key = "tf" + parentModule.getTf_moduleNameWithPre() + "." + table_fieldname[1];
					// 生成一个空记录以后，要对所有的有初始化值的manyToOne进行初始化
					Field[] fs = record.getClass().getDeclaredFields();
					for (Field f : fs) {
						if ((f.getAnnotation(ManyToOne.class) != null || f.getAnnotation(OneToOne.class) != null)
								&& f.getName().equals("tf" + parentModule.getTf_moduleNameWithPre()))
							try {
								CommonFunction.setPropertyToSuperClass(record, f.getName(),
										Class.forName(f.getType().getName()).newInstance());
							} catch (Exception e) {
								e.printStackTrace();
							}
					}
				}
			}
			log.debug("更新字段:" + key + ",value:" + value);
			ModuleServiceFunction.setValueToRecord(key, record, value);
		}
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public List<ValueText> getDistinctFieldWithComboData(String moduleName, String fieldName,
			List<SqlModuleFilter> filters, HttpServletRequest request) {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
		SqlGenerator generator = new SqlGenerator(module, request);
		generator.setFieldsOnlyThisField(fieldName);
		generator.setModuleFilters(filters);
		JSONArray dataArray = getData(generator, -1, 0);
		List<ValueText> result = new ArrayList<ValueText>();
		for (int i = 0; i < dataArray.size(); i++)
			if (dataArray.getJSONObject(i) != null) {
				String v = null;
				try {
					v = dataArray.getJSONObject(i).getString(fieldName);
				} catch (Exception e) {
				}
				if (v!= null && !v.toLowerCase().equals("null"))
					result.add(new ValueText(v, v));
			}
		return result;
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public List<ValueText> getModuleWithComboData(String moduleName, List<SqlModuleFilter> filters,
			HttpServletRequest request) {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
		SqlGenerator generator = new SqlGenerator(module, request);
		generator.setFieldsOnlyIdAndName();
		generator.setModuleFilters(filters);
		JSONArray dataArray = getData(generator, -1, 0);
		String idField = module.getTf_primaryKey();
		String nameField = module.getTf_nameFields();
		List<ValueText> result = new ArrayList<ValueText>();
		for (int i = 0; i < dataArray.size(); i++)
			result.add(new ValueText(dataArray.getJSONObject(i).getString(idField), dataArray
					.getJSONObject(i).getString(nameField)));
		return result;
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public List<ValueText> getModuleWithComboDataWithQuery(String moduleName,
			List<SqlModuleFilter> filters, HttpServletRequest request) {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
		SqlGenerator generator = new SqlGenerator(module, request);
		generator.setFieldsOnlyIdAndName();
		generator.setModuleFilters(filters);
		JSONArray dataArray = getData(generator, -1, 0);
		String idField = module.getTf_primaryKey();
		String nameField = module.getTf_nameFields();
		List<ValueText> result = new ArrayList<ValueText>();
		for (int i = 0; i < dataArray.size(); i++)
			result.add(new ValueText(dataArray.getJSONObject(i).getString(idField), dataArray
					.getJSONObject(i).getString(nameField)));
		return result;
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public List<TreeValueText> getModuleWithTreeData(String moduleName, Boolean allowParentValue,
			List<SqlModuleFilter> filters, HttpServletRequest request) {
		List<ValueText> vts = getModuleWithComboData(moduleName, filters, request);

		TreeValueText root = new TreeValueText("", "root");
		root.setLeaf(false);
		root.setExpanded(true);
		for (ValueText vt : vts) {
			root.getChildren().add(new TreeValueText(vt.getValue(), vt.getText()));
		}

		List<TreeValueText> deleted = new ArrayList<TreeValueText>();
		for (int i = root.getChildren().size() - 1; i > 0; i--) {
			// 对每一个编码，找到离其最近的上一级编码，把自己放在他的下面
			TreeValueText record = root.getChildren().get(i);
			for (int j = i - 1; j >= 0; j--) {
				TreeValueText p = root.getChildren().get(j);
				if (record.getValue().startsWith(p.getValue())) {
					p.getChildren().add(record);
					p.setExpanded(true);

					p.setDisabled(!allowParentValue && true);
					p.setLeaf(false);
					deleted.add(record);
					break;
				}
			}
		}
		root.getChildren().removeAll(deleted);
		List<TreeValueText> result = new ArrayList<TreeValueText>();
		result.addAll(root.getChildren());
		return result;
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public DataFetchResponseInfo getModuleData(String moduleName, DataFetchRequestInfo dsRequest,
			GridFilterData gridFilterData, HttpServletRequest request) {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);

		// 所有的导航tree产生的过滤条件
		List<SqlModuleFilter> treeAndParentFilters = new ArrayList<SqlModuleFilter>();

		if (dsRequest.getNavigateFilters() != null)
			for (SqlModuleFilter filter : dsRequest.getNavigateFilters()) {
				// 要处理一下，如果里面有的 formula 字段
				if (filter.getModuleName() != null) {
					_Module modu = SystemAndLoginInfoService.getModuleWithName(filter.getModuleName());
					_ModuleField field = modu.getFieldWithAsAndFieldName(modu.getTableAsName() + "."
							+ filter.getPrimarykey());
					if (field != null) {
						SqlField sqlField = new SqlField(filter.getModuleName(), filter.getTableAsName(),
								filter.getPrimarykey(), field.getTf_DBfieldName(), field.getTf_DBformula(),
								field.getTf_fieldType());
						filter.setPrimarykey(sqlField.getFieldFullName());
					}
				}

				treeAndParentFilters.add(filter);

			}
		// Iterator<String> key =
		// gridFilterData.getNavigateTreeSelected().keySet().iterator();
		// while (key.hasNext()) {
		// String s = (String) key.next();
		// TreeNodeRecord record = gridFilterData.getNavigateTreeSelected().get(s);
		// SqlModuleFilter moduleFilter = new SqlModuleFilter();
		// moduleFilter.setModuleName(record.getModuleName());
		// moduleFilter.setTableAsName(SystemAndLoginInfoService.getModuleWithName(
		// record.getModuleName()).getTableAsName());
		// moduleFilter.setPrimarykey(record.getIdkey());
		// moduleFilter.setEqualsValue(record.getIdvalue());
		// moduleFilter.setIsCodeLevel(record.getIsCodeLevel());
		// treeAndParentFilters.add(moduleFilter);
		// }

		// 如果有父模块约束，加入父模块约束
		addParentModuleFiltToSQLFilters(module, gridFilterData.getParentModuleFilter(),
				treeAndParentFilters);

		SqlGenerator generator = new SqlGenerator(module, request);

		generator.setModuleFilters(treeAndParentFilters);
		generator.setGridColumnNames(gridFilterData.getGridColumnNames());
		generator.setSearchText(gridFilterData.getSearchText());
		generator.setSorts(dsRequest.getSorts());
		generator.setGroupFieldname(gridFilterData.getGroupFieldName());
		Integer totalRow = getRecordCount(generator);
		log.debug("统计计录个数:" + totalRow);

		Integer startRow = dsRequest.getStartRow();
		Integer endRow = dsRequest.getEndRow();
		endRow = Math.min(endRow, totalRow - 1);

		JSONArray jsonArray = getData(generator, startRow, endRow);
		DataFetchResponseInfo response = new DataFetchResponseInfo();
		response.setStartRow(startRow);
		response.setEndRow(endRow);
		response.setTotalRows(totalRow);
		// if (dsRequest.getIsExport())
		response.setMatchingObjects(jsonArray);
		// else
		// response.setJsonMatchingItems(jsonArray.toString());

		return response;

	}

	
	private void addParentModuleFiltToSQLFilters(_Module module, SqlModuleFilter parentModuleFilter,
			List<SqlModuleFilter> treeAndParentFilters) {
		// 如果有父模块约束，加入父模块约束
		if (parentModuleFilter != null) {
			// 如果是附件的父模块约束，则要加入另外二个条件
			if (module.getTf_moduleName().equals(_Addition._ADDITION)) {
				SqlModuleFilter additionModuleIdFilter = new SqlModuleFilter();
				additionModuleIdFilter.setModuleName(module.getTf_moduleName());
				additionModuleIdFilter.setTableAsName(module.getTableAsName());
				additionModuleIdFilter.setPrimarykey(_Addition.MODULEID);
				additionModuleIdFilter.setEqualsValue(parentModuleFilter.getModuleId());
				treeAndParentFilters.add(additionModuleIdFilter);

				SqlModuleFilter additionModuleKeyIdFilter = new SqlModuleFilter();
				additionModuleKeyIdFilter.setModuleName(module.getTf_moduleName());
				additionModuleKeyIdFilter.setTableAsName(module.getTableAsName());
				additionModuleKeyIdFilter.setPrimarykey(_Addition.MODULEKEYID);
				additionModuleKeyIdFilter.setEqualsValue(parentModuleFilter.getEqualsValue());
				treeAndParentFilters.add(additionModuleKeyIdFilter);

			} else {
				treeAndParentFilters.add(parentModuleFilter);
			}
		}
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public Map<String, Integer> getParentModuleGroupByRecord(String moduleName, String groupField,
			SqlModuleFilter sqlModuleFilter, GridFilterData gridFilterData, Boolean reverseOrder,
			HttpServletRequest request) {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
		Map<String, Integer> result = new LinkedHashMap<String, Integer>();
		SqlGenerator generator = new SqlGenerator(moduleName, request);
		List<SqlModuleFilter> treeAndParentFilters = new ArrayList<SqlModuleFilter>();
		if (sqlModuleFilter != null)
			treeAndParentFilters.add(sqlModuleFilter);
		if (gridFilterData != null)
			addParentModuleFiltToSQLFilters(module, gridFilterData.getParentModuleFilter(),
					treeAndParentFilters);
		generator.setModuleFilters(treeAndParentFilters);
		String f = groupField;
		// groupField 是带 as 的 如 _t9901.tf_fieldname
		_ModuleField gf = module.getFieldWithAsAndFieldName(groupField);
		if (gf != null) {
			SqlField sqlField = new SqlField(moduleName, module.getTableAsName(),
					groupField.split("\\.")[1], gf.getTf_DBfieldName(), gf.getTf_DBformula(),
					gf.getTf_fieldType());
			f = sqlField.getFieldFullName();
		}
		String sql = generator.getGroupByIdAndCount(f, reverseOrder);
		Session session = systemBaseDAO.getSessionFactory().getCurrentSession();
		SQLQuery query = session.createSQLQuery(sql);
		List<?> results = null;
		try {
			results = query.list();
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (results != null)
			for (Object row : results) {
				Object[] rowObjects = (Object[]) row;
				if (rowObjects[0] != null)
					result.put(rowObjects[0].toString(), TypeChange.toInt(rowObjects[1]));
				else
					result.put(null, TypeChange.toInt(rowObjects[1]));
			}
		return result;
	}

	
	// @Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	// public int getModuleCountWithCondition(String moduleName,
	// List<SqlModuleFilter> sqlModuleFilters,
	// GridFilterData gridFilterData, HttpServletRequest request) {
	// _Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
	// SqlGenerator generator = new SqlGenerator(moduleName, request);
	// List<SqlModuleFilter> treeAndParentFilters = new
	// ArrayList<SqlModuleFilter>();
	// if (sqlModuleFilters != null)
	// treeAndParentFilters.addAll(sqlModuleFilters);
	// addParentModuleFiltToSQLFilters(module,
	// gridFilterData.getParentModuleFilter(),
	// treeAndParentFilters);
	// generator.setModuleFilters(treeAndParentFilters);
	// return getRecordCount(generator);
	//
	// }

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public int getModuleReccWithFilter(String moduleName, List<SqlModuleFilter> sqlModuleFilter,
			HttpServletRequest request) {
		SqlGenerator generator = new SqlGenerator(moduleName, request);
		generator.setModuleFilters(sqlModuleFilter);
		int result = getRecordCount(generator);
		return result;
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public JSONObject getModuleRecord(String moduleName, String keyValue, HttpServletRequest request) {
		_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
		SqlGenerator generator = new SqlGenerator(module, request);
		generator.setKeyValue(keyValue);
		JSONArray jsonArray = getData(generator, -1, 0);
		if (jsonArray.size() > 0)
			return jsonArray.getJSONObject(0);
		else
			return null;
	}

	
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public Integer getRecordCount(SqlGenerator generator) {

		String sql = generator.getCountSqlStatement();
		Session session = systemBaseDAO.getSessionFactory().getCurrentSession();
		SQLQuery query = session.createSQLQuery(sql);
		Integer countInteger = 0;
		try {
			countInteger = TypeChange.toInt(query.uniqueResult());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return countInteger;
	}

	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public JSONArray getData(SqlGenerator generator, Integer startRow, Integer endRow) {

		String sql = generator.getSqlStatment();
		Session session = systemBaseDAO.getSessionFactory().getCurrentSession();
		SQLQuery query = session.createSQLQuery(sql);
		if (startRow != -1) {
			query.setFirstResult(startRow);
			query.setMaxResults(endRow - startRow + 1);
		}
		generator.addScalar(query);

		List<?> results = null;
		try {
			results = query.list();
		} catch (Exception e) {
			e.printStackTrace();
		}
		JSONArray resultArray = new JSONArray();
		if (results != null)
			for (Object row : results) {
				Object[] rowObjects = (Object[]) row;
				Map<String, Object> objMap = new LinkedHashMap<String, Object>();
				JSONObject object = new JSONObject();
				int i = 0;
				for (SqlField field : generator.getFieldList())
					objMap.put(field.getFieldasScalar(),  rowObjects[i++]);
				for (SqlField field : generator.getJoinField())
					objMap.put(field.getFieldasScalar(),  rowObjects[i++]);
				object.putAll(objMap, JsonDateProcessor.us_jsonConfig);
				resultArray.add(object);
			}
		return resultArray;
	}

	public String getRecordNameValue(_Module module, Object record) {
		String result = "";
		try {
			result = (module.getTf_nameFields() != null && module.getTf_nameFields().length() > 0) ? Ognl
					.getValue(module.getTf_nameFields(), record).toString() : "未定义";
		} catch (Exception e) {
		}
		return result;
	}

	
	@Transactional(propagation = Propagation.REQUIRED)
	public _SystemOperateLog saveOperateLog(HttpServletRequest request, _Module module, String id,
			String name, String doword, String remark) {

		if (doword != null) {
			if (doword.equals("edit"))
				doword = "修改";
			else if (doword.equals("auditing"))
				doword = "审核";
			else if (doword.equals("cancelauditing"))
				doword = "取消审核";
			else if (doword.equals("approve"))
				doword = "审批";
			else if (doword.equals("cancelapprove"))
				doword = "取消审批";
		}

		_SystemOperateLog operateLog = new _SystemOperateLog();
		try {
			operateLog.setTf_date(new Date());
			operateLog.setTf_do(doword);
			operateLog.setTf_ipaddress(CommonFunction.getIpAddr(request));
			operateLog.setTf_moduleId(module.getTf_moduleId());
			operateLog.setTf_moduleTitle(module.getTf_title());
			operateLog.setTf_recordkey(id);
			if (name != null && name.length() > 50)
				name = name.substring(0, 50);
			operateLog.setTf_recordname(name);
			operateLog.setTf_remark(remark == null ? null : "-" + remark);
			UserSession userSession = SessionManage.getInstance().getUserSession(request.getSession());
			operateLog.setTf_userId(userSession.getUserId());
			operateLog.setTf_userName(userSession.getUserName());
			systemBaseDAO.save(operateLog);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return operateLog;
	}

	
	@Transactional(propagation = Propagation.REQUIRED)
	public _SystemOperateLog saveUploadExcelOperateLog(_Module module, String doword,
			String filename, OutputStream os, String remark, HttpServletRequest request) {

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos = (ByteArrayOutputStream) os;
		ByteArrayInputStream is = new ByteArrayInputStream(baos.toByteArray());
		return saveUploadExcelOperateLog(module, doword, filename, is, remark, request);

	}

	@SuppressWarnings("deprecation")
	@Transactional(propagation = Propagation.REQUIRED)
	public _SystemOperateLog saveUploadExcelOperateLog(_Module module, String doword,
			String filename, InputStream is, String remark, HttpServletRequest request) {

		_SystemOperateLog operateLog = new _SystemOperateLog();
		try {
			operateLog.setTf_date(new Date());
			operateLog.setTf_do(doword);
			operateLog.setTf_ipaddress(CommonFunction.getIpAddr(request));
			operateLog.setTf_moduleId(module.getTf_moduleId());
			operateLog.setTf_moduleTitle(module.getTf_title());
			operateLog.setTf_recordkey("未定义");
			if (filename != null && filename.length() > 50)
				filename = filename.substring(0, 50);
			operateLog.setTf_recordname(filename);
			operateLog.setTf_remark(remark == null ? null : "-" + remark);
			UserSession userSession = SessionManage.getInstance().getUserSession(request.getSession());
			operateLog.setTf_userId(userSession.getUserId());
			operateLog.setTf_userName(userSession.getUserName());

			// ByteArrayOutputStream baos = new ByteArrayOutputStream();
			// baos = (ByteArrayOutputStream) os;
			// ByteArrayInputStream is = new ByteArrayInputStream(baos.toByteArray());
			operateLog.setTf_hasfiledata(true);
			operateLog.setTf_filedata(Hibernate.createBlob(is));
			systemBaseDAO.save(operateLog);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return operateLog;
	}

}
